package com.cwl.data.queue;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @program: data-structure
 * @description: 阻塞队列
 * @author: ChenWenLong
 * @create: 2019-09-10 11:06
 **/
public class MyBlockQueue<T> {

    private int size;
    private Object[] queue;

    private Lock lock = new ReentrantLock();
    private Condition full = lock.newCondition();
    private Condition empty = lock.newCondition();

    private int index;
    private int removeIndex;
    private int currLen;

    /**
     * 功能描述:
     * 〈创建默认大小为10的阻塞队列〉
     *
     * @params : []
     * @return :
     * @author : cwl
     * @date : 2019/9/10 11:07
     */
    public MyBlockQueue() {
        this(10);
    }

    /**
     * 功能描述:
     * 〈创建指定大小的阻塞队列〉
     *
     * @params : [size]
     * @return :
     * @author : cwl
     * @date : 2019/9/10 11:07
     */
    public MyBlockQueue(int size) {
        this.index = 0;
        this.removeIndex = 0;
        this.currLen = 0;
        this.size = size;
        queue = new Object[size];
    }

    /**
     * 功能描述:
     * 〈往阻塞队列中添加元素〉
     *
     * @params : [element]
     * @return : void
     * @author : cwl
     * @date : 2019/9/10 11:10
     */
    public void push(T element) throws InterruptedException {
        lock.lock();
        try {
            while (currLen == size) {
                System.out.println("队列满。。。");
                full.await();
            }
            queue[index] = element;
            if (++index == size) {
                index = 0;
            }
            currLen++;
            empty.signal();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 功能描述:
     * 〈从阻塞队列中获取元素〉
     *
     * @params : []
     * @return : T
     * @author : cwl
     * @date : 2019/9/10 11:10
     */
    public T pop() throws InterruptedException {
        lock.lock();
        try {
            while (currLen == 0) {
                System.out.println("队列空。。。");
                empty.await();
            }
            Object obj = queue[removeIndex];
            if (++removeIndex == size) {
                removeIndex = 0;
            }
            currLen--;
            full.signal();
            return (T) obj;
        } finally {
            lock.unlock();
        }
    }
}
